﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Antlr.Runtime;
using PSLib.Parsing.Lua;

namespace PSLib.Parsing.Common
{
    public static class TokensRecognizer
    {
        public static readonly List<string> LuaKeyWords = new List<string>()
        {
            "do", 
		    "end", 
		    "while", 
		    "repeat", 
		    "until", 
		    "if", 
		    "then", 
		    "elseif", 
		    "else", 
		    "for", 
		    "in", 
		    "function", 
		    "local", 
		    "return", 
		    "break",
            "#",
        };

        public static readonly List<string> LuaConstants = new List<string>()
        {
            "false", 
		    "true", 
		    "nil", 
            "...",
        };

        public static readonly List<string> LuaPunctuation = new List<string>()
        {
            ";", 
		    ",", 
		    ".", 
            ":", 
            "(", 
		    ")", 
		    "[", 
		    "]", 
		    "{", 
		    "}", 
        };

        public static readonly List<string> LuaOperators = new List<string>()
        {
            "'='", 
		   	"'+'", 
		    "'-'", 
		    "'*'", 
		    "'/'", 
		    "'^'", 
		    "'%'", 
		    "'..'", 
		    "'<'", 
		    "'<='", 
		    "'>'", 
		    "'>='", 
		    "'=='", 
		    "'~='", 
		    "'and'", 
		    "'or'",
            "'not'",
        };

        public static RecognizedTokenType Recognize(string tokenText)
        {
            RecognizedTokenType type = RecognizedTokenType.Unknown;
            if (!string.IsNullOrEmpty(tokenText))
            {
                if (type == RecognizedTokenType.Unknown && tokenText.Length == 1)
                {
                    if (char.IsPunctuation(tokenText[0])) type = RecognizedTokenType.Punctuation;
                }

                if (TokensRecognizer.LuaKeyWords.Contains(tokenText)) type = RecognizedTokenType.Keyword;
                else if (TokensRecognizer.LuaConstants.Contains(tokenText)) type = RecognizedTokenType.Constant;
                else if (TokensRecognizer.LuaPunctuation.Contains(tokenText)) type = RecognizedTokenType.Punctuation;
                else if (TokensRecognizer.LuaOperators.Contains(tokenText)) type = RecognizedTokenType.Operator;
                else
                {
                    int resInt = 0;
                    double resDouble = 0;
                    if (Int32.TryParse(tokenText, out resInt)) type = RecognizedTokenType.Digit;
                    else if (Double.TryParse(tokenText, out resDouble)) type = RecognizedTokenType.Digit;
                    else
                    {
                        if (tokenText[0] == '_' || char.IsLetterOrDigit(tokenText[0]))
                        {
                            bool brokenName = false;
                            for (int i = 1; i < tokenText.Length; i++)
                            {
                                brokenName = !char.IsLetterOrDigit(tokenText[i]);
                                if (brokenName) break;
                            }
                            if (!brokenName) type = RecognizedTokenType.Word;
                        }
                    }
                }
            }
            return type;
        }

        public static RecognizedToken Recognize(IToken token)
        {
            RecognizedTokenType type = RecognizedTokenType.Unknown;

            switch (token.Type)
            {
                case LuaParser.NORMALSTRING:
                case LuaParser.LONGSTRING:
                case LuaParser.CHARSTRING: 
                    type = RecognizedTokenType.String; 
                    break;
                case LuaParser.INT:
                case LuaParser.HEX:
                case LuaParser.FLOAT:
                case LuaParser.EXP:
                    type = RecognizedTokenType.Digit;
                    break;
                case LuaParser.COMMENT:
                case LuaParser.LINE_COMMENT:
                    type = RecognizedTokenType.Comment;
                    break;
                case LuaParser.NAME:
                    type = RecognizedTokenType.Word;
                    break;
            }
            if (type == RecognizedTokenType.Unknown) type = TokensRecognizer.Recognize(token.Text);
           
            return new RecognizedToken(token, type);
        }
    }
}
